﻿using System;
using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using Lime49.UI;
using LockCrypt.Core;
using LockCrypt.DAL;
using LockCrypt.Properties;

namespace LockCrypt {
    /// <summary>
    /// Dialog for exporting databases.
    /// </summary>
    public partial class WinCreateDatabase : Window {
        /// <summary>
        /// Initializes a new <see cref="WinCreateDatabase"/>.
        /// </summary>
        public WinCreateDatabase() {
            InitializeComponent();
            descriptorPathChooser.DefaultExtension = ".lcd";
            descriptorPathChooser.FilterString = string.Format("{0}|*.*|{1} (*.lcd)|*.lcd", I18nUtils.GetString("Strings", "AllFiles"), I18nUtils.GetString("Strings", "DatabaseDescriptor"));
            descriptorPathChooser.FilterIndex = 2;
        }

        /// <summary>
        /// Initializes a new <see cref="WinCreateDatabase"/>.
        /// </summary>
        /// <param name="provider">The provider whose attributes to pre-select.</param>
        public WinCreateDatabase(IDbProvider provider)
            : this() {
            dbSelector.Provider = provider;
            dbSelector.DatabaseMode = provider.DatabaseType;
            dbSelector.EncryptionAlgorithm = provider.Encryption.EncryptionAlgorithm;
        }

        /// <summary>
        /// Initializes a new <see cref="WinCreateDatabase"/>.
        /// </summary>
        /// <param name="provider">The provider whose attributes to pre-select.</param>
        /// <param name="openOnStartup"><c>true</c> if the 'open on startup' checkbox should be pre-checked.</param>
        public WinCreateDatabase(IDbProvider provider, bool openOnStartup)
            : this(provider) {
            chkOpenOnStartup.IsChecked = openOnStartup;
        }

        /// <summary>
        /// Initializes a new <see cref="WinCreateDatabase"/>.
        /// </summary>
        /// <param name="fileName">Name of the file to create.</param>
        /// <param name="type">The database type to pre-select.</param>
        /// <param name="encryption">The encryption algorithm to pre-select.</param>
        public WinCreateDatabase(string fileName, Constants.DatabaseType type, EncryptionProviders encryption) 
            :this() {
            dbSelector.DatabasePath = fileName;
            dbSelector.DatabaseMode = type;
            dbSelector.EncryptionAlgorithm = encryption;
        }

        /// <summary>
        /// Checks and disables the 'Open now' checkbox when the 'Open on startup' checkbox is checked/unchecked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ToggleOpenOnStartup(object sender, RoutedEventArgs e) {
            if(chkOpenOnStartup.IsChecked == true) {
                chkOpenNow.IsChecked = true;
                chkOpenNow.IsEnabled = false;
            } else {
                chkOpenNow.IsChecked = false;
                chkOpenNow.IsEnabled = true;
            }
        }

        /// <summary>
        /// Validates the credentials entered.
        /// </summary>
        /// <returns><c>true</c> if the credentials are valid, otherwise <c>false</c>.</returns>
        private bool ValidateDatabase() {
            bool valid = true;
            if(!dbSelector.ValidateSettings()) {
                valid = false;
            } else if(chkGenerateDescriptor.IsChecked == true && string.IsNullOrEmpty(descriptorPathChooser.SelectedPath)) {
                DialogBox.ShowAlert(this, I18nUtils.GetString("Errors", "InvalidFilename"), I18nUtils.GetString("Strings", "DatabaseDescriptor"));
                descriptorPathChooser.Focus();
                valid = false;
            } else if(!descriptorPathChooser.ValidatePath()) {
                valid = false;
            }
            return valid;
        }

        /// <summary>
        /// Closes the window.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void CloseWindow(object sender, ExecutedRoutedEventArgs e) {
            DialogResult = false;
        }

        /// <summary>
        /// Creates a new database.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void CreateDatabase(object sender, ExecutedRoutedEventArgs e) {
            if(ValidateDatabase()) {
                IDbProvider newProvider = null;
                try {
                    newProvider = dbSelector.Provider;
                } catch(Exception ex) {
                    DialogBox.ShowAlert(this, I18nUtils.GetString("Errors", "ErrorCreatingDBFmt", ex.Message), I18nUtils.GetString("Errors", "Error"));
                    return;
                }
                if(chkOpenOnStartup.IsChecked == true) {
                    Settings.Default.AutoOpenOnStartup = true;
                    Settings.Default.DatabaseMode = newProvider.DatabaseType.ToString();
                    Settings.Default.DatabaseConnectionString = newProvider.ConnectionString;
                    Settings.Default.EncryptionAlgorithm = newProvider.Encryption.EncryptionAlgorithm.ToString();
                    Settings.Default.Save();
                    WPFConfigurationManager.Configure();
                }
                if(chkOpenNow.IsChecked == true) {
                    DalConfigurationManager.Provider = newProvider;
                }
                BackgroundWorker worker = new BackgroundWorker();
                worker.DoWork += (s, dwe) => newProvider.CreateDatabase();
                worker.RunWorkerCompleted += (s, rwe) => {
                    if(rwe.Error != null) {
                        DialogBox.ShowAlert(this, rwe.Error.Message, I18nUtils.GetString("Errors", "Error"));
                    } else {
                        if(chkGenerateDescriptor.IsChecked == true) {
                            try {
                                LockCryptWPFBLL.SaveDescriptor(newProvider, descriptorPathChooser.SelectedPath);
                            } catch(Exception ex) {
                                DialogBox.ShowAlert(this, "Error generating descriptor: " + ex.Message, I18nUtils.GetString("Errors", "Error"));
                            }
                        }
                        DialogResult = true;
                    }
                };
                worker.RunWorkerAsync();
                while(worker.IsBusy) {
                    Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate() { }));
                }
            }
        }

        /// <summary>
        /// Updates the descriptor save path when the database filename changes.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void dbSelector_PathChanged(object sender, EventArgs e) {
            try {
                FileInfo pathInfo = new FileInfo(dbSelector.DatabasePath);
                string directoryName,
                       fileName;
                if(Directory.Exists(pathInfo.FullName)) {
                    directoryName = pathInfo.FullName;
                    fileName = string.Format("LockCrypt-{0}.lcd", DateTime.Now.ToString("yyyy-MM-dd"));
                } else {
                    directoryName = pathInfo.Directory.FullName;
                    fileName = System.IO.Path.GetFileNameWithoutExtension(pathInfo.FullName)+".lcd";
                }
                string descriptorPath = System.IO.Path.Combine(directoryName, fileName);
                descriptorPathChooser.SelectedPath = descriptorPath;
            } catch {
            }
        }
    }
}
